package com.mjgy.service.impl;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.common.utils.R;
import com.mjgy.config.SysConfig;
import com.mjgy.entity.AlbumUnlocker;
import com.mjgy.entity.ContactWayWhiteList;
import com.mjgy.entity.MUserEntity;
import com.mjgy.entity.MemberEntity;
import com.mjgy.entity.MessageEntity;
import com.mjgy.entity.PayLog;
import com.mjgy.entity.PhotoViewerEntity;
import com.mjgy.entity.RechargeTypeEntity;
import com.mjgy.repository.AlbumUnlockerRepository;
import com.mjgy.repository.ContactWayWhiteListRepository;
import com.mjgy.repository.MUserRepository;
import com.mjgy.repository.MemberRepository;
import com.mjgy.repository.MessageRepository;
import com.mjgy.repository.PayLogRepository;
import com.mjgy.service.MUserService;
import com.mjgy.service.PayService;
import com.mjgy.service.PhotoViewerService;
import com.mjgy.utils.Const;
import com.mjgy.utils.HttpRequest;
import com.mjgy.utils.WXPayUtil;

import net.sf.json.JSONObject;

/**
* @Description: TODO
* @author LGC
* @date 2018年10月12日
* @version V1.0
*/
@Service
@Transactional
public class PayServiceImpl implements PayService {
	
	private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
	
	@Autowired
	private EntityManager em;
	
	@Autowired
	private PayLogRepository payLogRepository;
	@Autowired
	private MemberRepository memberRepository;
	@Autowired
	private AlbumUnlockerRepository albumUnlockerRepository;
	@Autowired
	private ContactWayWhiteListRepository contactWayWhiteListRepository;
	@Autowired
	private MUserRepository mUserRepository;
	@Autowired
	private MessageRepository messageRepository;
	@Autowired
	private MUserService mUserService;
	@Autowired
	private PhotoViewerService photoViewerService;

	@Override
	public R getWXPayOrder(HttpServletRequest request, Long userId, Long collecterId, double payMoney, int type, Long rechargeId, Long serviceId) {
		Date curDate = new Date();
		Timestamp curTime = new Timestamp(curDate.getTime());
		JSONObject jo = new JSONObject();
		String outTradeNo = "";
		try {
			String appId = SysConfig.appId;
			String mchId = SysConfig.mchId;
			String paternerKey = SysConfig.paternerKey;
			
			String body = "YueYeWXPay";
			outTradeNo = Const.getOutTradeNo();
			String totalFee = String.valueOf((int) payMoney);
			String spbillCreateIp = "39.108.51.202";
			String notifyUrl = "http://" + spbillCreateIp + ":8080/yueye/pay/wxPayNotify";
			String tradeType = "APP";
			Map<String, String> params = new HashMap<>();
			params.put("appid", appId);
			params.put("mch_id", mchId);
			params.put("nonce_str", WXPayUtil.generateNonceStr());
			params.put("body", body);
			params.put("out_trade_no", outTradeNo);
			params.put("total_fee", totalFee);
			params.put("spbill_create_ip", spbillCreateIp);
			params.put("notify_url", notifyUrl);
			params.put("trade_type", tradeType);
			String sign = WXPayUtil.generateSignature(params, paternerKey);
			params.put("sign", sign);
			
			String reqParam = WXPayUtil.mapToXml(params);
			String resMsg = HttpRequest.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", reqParam);
			if(StringUtils.isEmpty(resMsg)) {
				return R.error(201, "请求接口错误");
			}
			
			Map<String, String> retMap = WXPayUtil.xmlToMap(resMsg);
			if(!retMap.get("return_code").equals("SUCCESS")) {
				return R.error(202, retMap.get("return_msg"));
			}
			
			// 判断签名是否正确
			boolean isSignValid = WXPayUtil.isSignatureValid(retMap, paternerKey);
			if(!isSignValid) {
				return R.error(203, "签名验证失败");
			}
			
			// 再次签名（微信支付必要）
			Map<String, String> startPayParams = new HashMap<>();
			String startPayNonceStr = WXPayUtil.generateNonceStr();
			startPayParams.put("appid", appId);
			startPayParams.put("partnerid", mchId);
			startPayParams.put("prepayid", retMap.get("prepay_id"));
			startPayParams.put("package", "Sign=WXPay");
			startPayParams.put("noncestr", startPayNonceStr);
			startPayParams.put("timestamp", String.valueOf(curTime.getTime() / 1000));
			String startPaySign = WXPayUtil.generateSignature(startPayParams, paternerKey);
			
			jo.put("appid", appId);
			jo.put("partnerid", mchId);
			jo.put("prepayid", retMap.get("prepay_id"));
			jo.put("package", "Sign=WXPay");
			jo.put("noncestr", startPayNonceStr);
			jo.put("timestamp", curTime.getTime() / 1000);
			jo.put("timestamp2", curTime.getTime());
			jo.put("sign", startPaySign);
			
			PayLog payLog = new PayLog();
			payLog.setPayerId(userId);
			payLog.setCollecterId(collecterId);
			payLog.setOutTradeNo(outTradeNo);
			payLog.setType(type);
			payLog.setPayWay(0);
			payLog.setAmount(BigDecimal.valueOf(payMoney).divide(new BigDecimal(100)));
			payLog.setStatus(0);
			payLog.setCreateTime(new Date());
			payLog.setServiceId(serviceId);
			if(type == 4) {
				payLog.setServiceId(rechargeId);
			}
			em.persist(payLog);
			
			return R.success().put("data", jo);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return R.error();
	}

	@Override
	public String wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
		Map<String, String> resParams = new HashMap<>();
		try {
			InputStream inputStream = request.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
			String line = null;
			StringBuffer sb = new StringBuffer();
			while((line = br.readLine()) != null) {
				sb.append(line);
			}
			br.close();
			inputStream.close();
			Map<String, String> retParams = WXPayUtil.xmlToMap(sb.toString());
			if(retParams.get("return_code").equals("SUCCESS")) { // 返回成功
				if(retParams.get("result_code").equals("SUCCESS")) { // 业务返回成功
					if(WXPayUtil.isSignatureValid(retParams, SysConfig.paternerKey)) { // 验证签名
						String outTradeNo = retParams.get("out_trade_no");
						logger.error(outTradeNo);
						PayLog payLog = payLogRepository.findOneByOutTradeNo(outTradeNo);
						if(payLog != null && payLog.getStatus() == 0) {
							logger.error("payLogType：" + payLog.getType());
							if(payLog.getType() == 0){	//付费查看联系方式
								this.signContactWay(payLog.getPayerId(), payLog.getCollecterId(), payLog.getAmount());
							}
							if(payLog.getType() == 1){	//付费查看红包图片
								this.signPayPhoto(payLog.getCollecterId(), payLog.getPayerId(), payLog.getServiceId(), payLog.getAmount());
							}
							if(payLog.getType() == 2){	//付费解锁相册
								this.signAlbum(payLog.getCollecterId(), payLog.getPayerId());
							}
							if(payLog.getType() == 4) { // 会员充值
								Long rechargeId = payLog.getServiceId();
								RechargeTypeEntity recharge = em.find(RechargeTypeEntity.class, rechargeId);
								MemberEntity member = memberRepository.findByUserId(payLog.getPayerId());
								if(member != null) { // 当前充值用户有会员，则继续续费
									member.setTotalDays(member.getTotalDays() + recharge.getRechargeDays());
									member.setSurplusDays(member.getSurplusDays() + recharge.getRechargeDays());
									member.setUpdateTime(new Date());
									em.merge(member);
								} else {
									member = new MemberEntity();
									member.setUserId(payLog.getPayerId());
									member.setTotalDays(recharge.getRechargeDays());
									member.setSurplusDays(recharge.getRechargeDays());
									member.setCreateTime(new Date());
									em.persist(member);
								}
								MUserEntity user = em.find(MUserEntity.class, payLog.getPayerId());
								user.setIdentity(1);
								em.merge(user);
							}
							payLog.setStatus(1);
							em.merge(payLog);
							
							resParams.put("return_code", "SUCCESS");
							resParams.put("return_msg", "OK");
							return WXPayUtil.mapToXml(resParams);
						}	
					}
				} else {
					resParams.put("return_code", "FAIL");
					resParams.put("return_msg", "签名验证失败");
					return WXPayUtil.mapToXml(resParams);
				}
			}
			
			resParams.put("return_code", "FAIL");
			resParams.put("return_msg", "参数验证失败");
			return WXPayUtil.mapToXml(resParams);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}

	@Override
	public R signContactWay(Long checkerId, Long userId, BigDecimal payMoney){
		if(checkerId == null){
			return R.error(202, "用户ID不能为空");
		}
		if(userId == null){
			return R.error(202, "查看联系方式的人ID不能为空");
		}
		ContactWayWhiteList contactWayWhiteList = new ContactWayWhiteList();
		contactWayWhiteList.setCheckerId(checkerId);
		contactWayWhiteList.setUserId(userId);
		contactWayWhiteList.setCreateTime(new Date());
		contactWayWhiteList.setType(0);	//付费查看联系方式
		Integer count = contactWayWhiteListRepository.countByUserIdAndCheckerId(contactWayWhiteList.getUserId(), contactWayWhiteList.getCheckerId());
		if(count > 0){
			return R.error(202, "该联系方式已标记，请勿重复标记");
		}
		
		//付费查看联系方式增加女性钱包金额
		mUserService.updateWallet(userId, payMoney);
		contactWayWhiteListRepository.save(contactWayWhiteList);
		
		//发送消息
		MessageEntity messageEntity = new MessageEntity();
		messageEntity.setIsChecked(0);
		messageEntity.setType("2");
		messageEntity.setSenderId(contactWayWhiteList.getCheckerId());
		messageEntity.setUserId(contactWayWhiteList.getUserId());
		messageEntity.setSendTime(new Date());
		messageEntity.setContent("付费查看了你的联系方式");
		messageRepository.save(messageEntity);
				
		return R.success();
	}

	@Override
	public R signPayPhoto(Long userId, Long viewerId, Long photoId, BigDecimal payMoney) {
		PhotoViewerEntity photoViewerEntity = new PhotoViewerEntity();
		photoViewerEntity.setUserId(userId);
		photoViewerEntity.setViewerId(viewerId);
		photoViewerEntity.setPhotoId(photoId);
		photoViewerEntity.setType(2);
		photoViewerService.save(photoViewerEntity);
		
		//付费查看联系方式增加女性钱包金额
		mUserService.updateWallet(userId, payMoney);
		
		//发消息
		MessageEntity messageEntity = new MessageEntity();
		messageEntity.setIsChecked(0);
		messageEntity.setType("2");
		messageEntity.setSenderId(photoViewerEntity.getViewerId());
		messageEntity.setUserId(photoViewerEntity.getUserId());
		messageEntity.setSendTime(new Date());
		messageEntity.setContent("付费查看了你的红包图片");
		messageRepository.save(messageEntity);
		
		return R.success();
	}

	@Override
	public R signAlbum(Long userId, Long unlockerId) {
		AlbumUnlocker albumUnlocker = new AlbumUnlocker();
		albumUnlocker.setUserId(userId);
		albumUnlocker.setUnlockerId(unlockerId);
		albumUnlocker.setType(0);
		albumUnlocker.setCreateTime(new Date());
		
		Integer count = albumUnlockerRepository.countByUserIdAndUnlockerId(albumUnlocker.getUnlockerId(), albumUnlocker.getUserId());
		if(count > 0){
			return R.error(202, "该付费相册已标记，请勿重复标记");
		}
		
		//增加女性钱包金额
		MUserEntity mUserEntity = mUserRepository.findOne(albumUnlocker.getUserId());
		if(mUserEntity == null){
			return R.error(202, "被解锁付费相册的用户不存在");
		}
		mUserService.updateWallet(albumUnlocker.getUserId(), 
				mUserEntity.getAlbumAmount() == null?BigDecimal.valueOf(10) : mUserEntity.getAlbumAmount());
		albumUnlockerRepository.save(albumUnlocker);
		
		//发送消息
		MessageEntity messageEntity = new MessageEntity();
		messageEntity.setIsChecked(0);
		messageEntity.setType("2");
		messageEntity.setSenderId(albumUnlocker.getUnlockerId());
		messageEntity.setUserId(albumUnlocker.getUserId());
		messageEntity.setSendTime(new Date());
		messageEntity.setContent("付费查看了你的相册");
		messageRepository.save(messageEntity);
		
		return R.success();
	}

	@Override
	public R payLogInfo(Map<String, Object> params) {
		StringBuilder sql = new StringBuilder();
		sql.append("select pl.type \n");
		sql.append("      ,pl.amount \n");
		sql.append("      ,DATE_FORMAT(pl.create_time, '%Y-%m-%d') \n");
		sql.append("      ,DATE_FORMAT(pl.create_time, '%T') \n");
		sql.append("from pay_log pl \n");
		sql.append("where pl.payer_id = :userId \n");
		sql.append("and pl.status = 1 \n");
		if(!StringUtils.isEmpty((String) params.get("dateValue"))) {
			sql.append("and DATE_FORMAT(pl.create_time, '%Y-%m-%d') between :start and :end \n");
		}
		sql.append("order by pl.create_time desc \n");
		
		Query query = em.createNativeQuery(sql.toString());
		query.setParameter("userId", params.get("id"));	
		if(!StringUtils.isEmpty((String) params.get("dateValue"))) {
			String dateValue = (String) params.get("dateValue");
			String[] dates = dateValue.split(",");
			query.setParameter("start", dates[0]);
			query.setParameter("end", dates[1]);
		}	
		
		List resultList = query.getResultList();
		int defIndex = 0;
		Map<String, List<String>> map = new LinkedHashMap<>();
		for(int i = 0; i < resultList.size(); i++) {
			List<String> infoList = new ArrayList<>();

			Object row = resultList.get(i);
			Object[] cells = (Object[]) row;
			int type = (int) cells[0];
			BigDecimal amount = (BigDecimal) cells[1];
			String day = (String) cells[2];
			String time = (String) cells[3];
			String typeTmp = "";
			if(type == 0) {
				typeTmp = "查看联系方式";
			} else if(type == 1) {
				typeTmp = "查看红包图片";
			} else if(type == 2) {
				typeTmp = "查看付费相册";
			} else if(type == 3) {
				typeTmp = "发广播";
			} else if(type == 4) {
				typeTmp = "购买会员";
			}
			String info = String.format("%s, %s花费%s元", time, typeTmp, amount);
			infoList.add(info);
			map.put(day, infoList);
			// 筛选重复日期记录
			for(int j = i + 1; j < resultList.size(); j++) {
				Object rowJ = resultList.get(j);
				Object[] cellsJ = (Object[]) rowJ;
				String dayJ = (String) cellsJ[2];
				if(dayJ.equals(day)) {
					int typeJ = (int) cellsJ[0];
					BigDecimal amountJ = (BigDecimal) cellsJ[1];
					String timeJ = (String) cellsJ[3];
					String typeTmpJ = "";
					if(typeJ == 0) {
						typeTmpJ = "查看联系方式";
					} else if(typeJ == 1) {
						typeTmpJ = "查看红包图片";
					} else if(typeJ == 2) {
						typeTmpJ = "查看付费相册";
					} else if(typeJ == 3) {
						typeTmpJ = "发广播";
					} else if(typeJ == 4) {
						typeTmpJ = "购买会员";
					}
					String infoJ = String.format("%s, %s花费%s元", timeJ, typeTmpJ, amountJ);
					infoList.add(infoJ);
					map.put(dayJ, infoList);
//					defIndex = j;
					i = j;
				} else {
					break;
				}
			}
			
//			i = defIndex;
		}
		
		return R.success().put("data", map);
	}

	@Override
	public R incomeInfo(Map<String, Object> params) {
		StringBuilder sql = new StringBuilder();
		sql.append("select pl.type \n");
		sql.append("      ,pl.amount \n");
		sql.append("      ,DATE_FORMAT(pl.create_time, '%Y-%m-%d') \n");
		sql.append("      ,DATE_FORMAT(pl.create_time, '%T') \n");
		sql.append("from pay_log pl \n");
		sql.append("where pl.collecter_id = :userId \n");
		sql.append("and pl.status = 1 \n");
		if(!StringUtils.isEmpty((String) params.get("dateValue"))) {
			sql.append("and DATE_FORMAT(pl.create_time, '%Y-%m-%d') between :start and :end \n");
		}
		sql.append("order by pl.create_time desc \n");
		
		Query query = em.createNativeQuery(sql.toString());
		query.setParameter("userId", params.get("id"));	
		if(!StringUtils.isEmpty((String) params.get("dateValue"))) {
			String dateValue = (String) params.get("dateValue");
			String[] dates = dateValue.split(",");
			query.setParameter("start", dates[0]);
			query.setParameter("end", dates[1]);
		}
		List resultList = query.getResultList();
		int defIndex = 0;
		Map<String, List<String>> map = new LinkedHashMap<>();
		for(int i = 0; i < resultList.size(); i++) {
			List<String> infoList = new ArrayList<>();

			Object row = resultList.get(i);
			Object[] cells = (Object[]) row;
			int type = (int) cells[0];
			BigDecimal amount = (BigDecimal) cells[1];
			String day = (String) cells[2];
			String time = (String) cells[3];
			String typeTmp = "";
			if(type == 0) {
				typeTmp = "由联系方式";
			} else if(type == 1) {
				typeTmp = "由红包图片";
			} else if(type == 2) {
				typeTmp = "由付费相册";
			}
			String info = String.format("%s, %s收入%s元", time, typeTmp, amount);
			infoList.add(info);
			map.put(day, infoList);
			// 筛选重复日期记录
			for(int j = i + 1; j < resultList.size(); j++) {
				Object rowJ = resultList.get(j);
				Object[] cellsJ = (Object[]) rowJ;
				String dayJ = (String) cellsJ[2];
				if(dayJ.equals(day)) {
					int typeJ = (int) cellsJ[0];
					BigDecimal amountJ = (BigDecimal) cellsJ[1];
					String timeJ = (String) cellsJ[3];
					String typeTmpJ = "";
					if(typeJ == 0) {
						typeTmpJ = "由联系方式";
					} else if(typeJ == 1) {
						typeTmpJ = "由红包图片";
					} else if(typeJ == 2) {
						typeTmpJ = "由付费相册";
					}	
					String infoJ = String.format("%s, %s收入%s元", timeJ, typeTmpJ, amountJ);
					infoList.add(infoJ);
					map.put(dayJ, infoList);
//					defIndex = j;
					i = j;
				} else {
//					defIndex ++;
					break;
				}
			}
			
//			i = defIndex;
		}
		
		return R.success().put("data", map);
	}

}
